
<!DOCTYPE html>

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />

    <title>Embedding Leo with the leoBridge module &#8212; Leo 6.7.2 documentation</title>
    <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
    <link rel="stylesheet" type="text/css" href="_static/classic.css" />
    <link rel="stylesheet" type="text/css" href="_static/custom.css" />
    
    <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
    <script src="_static/jquery.js"></script>
    <script src="_static/underscore.js"></script>
    <script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
    <script src="_static/doctools.js"></script>
    <script src="_static/sphinx_highlight.js"></script>
    
    <script src="_static/sidebar.js"></script>
    
    <link rel="index" title="Index" href="genindex.html" />
    <link rel="search" title="Search" href="search.html" />
    <link rel="next" title="ILeo: Leo’s IPython Bridge" href="IPythonBridge.html" />
    <link rel="prev" title="Using Vim with Leo" href="vimBindings.html" /> 
  </head><body>
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="genindex.html" title="General Index"
             accesskey="I">index</a></li>
        <li class="right" >
          <a href="IPythonBridge.html" title="ILeo: Leo’s IPython Bridge"
             accesskey="N">next</a> |</li>
        <li class="right" >
          <a href="vimBindings.html" title="Using Vim with Leo"
             accesskey="P">previous</a> |</li>
        <li class="nav-item nav-item-0"><a href="leo_toc.html">Leo 6.7.2 documentation</a> &#187;</li>
          <li class="nav-item nav-item-1"><a href="leoandotherprograms.html" accesskey="U">Leo and Other Programs</a> &#187;</li>
        <li class="nav-item nav-item-this"><a href="">Embedding Leo with the leoBridge module</a></li> 
      </ul>
    </div>  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body" role="main">
            
  <section id="embedding-leo-with-the-leobridge-module">
<h1>Embedding Leo with the leoBridge module<a class="headerlink" href="#embedding-leo-with-the-leobridge-module" title="Permalink to this heading">¶</a></h1>
<p>The leoBridge module allows complete access to all aspects of Leo from other
Python programs running independently of Leo. Let us call such a program a
<strong>host</strong> program. Using the leoBridge module, host programs can get access to:</p>
<ul class="simple">
<li><p>all of Leo’s source code,</p></li>
<li><p>the contents of any .leo file,</p></li>
<li><p>the commander of any .leo file.</p></li>
</ul>
<div class="contents local topic" id="contents">
<p class="topic-title">Contents</p>
<ul class="simple">
<li><p><a class="reference internal" href="#the-basics" id="id1">The basics</a></p></li>
<li><p><a class="reference internal" href="#running-leobridge-from-within-leo" id="id2">Running leoBridge from within Leo</a></p></li>
</ul>
</div>
<section id="the-basics">
<h2><a class="toc-backref" href="#id1">The basics</a><a class="headerlink" href="#the-basics" title="Permalink to this heading">¶</a></h2>
<p>Host programs use the leoBridge module as follows:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">leo.core.leoBridge</span> <span class="k">as</span> <span class="nn">leoBridge</span>

<span class="n">controller</span> <span class="o">=</span> <span class="n">leoBridge</span><span class="o">.</span><span class="n">controller</span><span class="p">(</span><span class="n">gui</span><span class="o">=</span><span class="s1">&#39;nullGui&#39;</span><span class="p">,</span>
    <span class="n">loadPlugins</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>  <span class="c1"># True: attempt to load plugins.</span>
    <span class="n">readSettings</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="c1"># True: read standard settings files.</span>
    <span class="n">silent</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>      <span class="c1"># True: don&#39;t print signon messages.</span>
    <span class="n">verbose</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>     <span class="c1"># True: print informational messages.</span>

<span class="n">g</span> <span class="o">=</span> <span class="n">controller</span><span class="o">.</span><span class="n">globals</span><span class="p">()</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">controller</span><span class="o">.</span><span class="n">openLeoFile</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
</pre></div>
</div>
<p>Let us look at these statements in detail. The first two statements import the leoBridge module and create a <strong>bridge controller</strong>. In effect, these statements embed an invisible copy of Leo into the host program. This embedded copy of Leo uses a null gui, which simulates all aspects of Leo’s normal gui code without creating any screen objects.</p>
<p>The statement:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">g</span> <span class="o">=</span> <span class="n">controller</span><span class="o">.</span><span class="n">globals</span><span class="p">()</span>
</pre></div>
</div>
<p>provides access to Leo’s leoGlobals module, and properly inits globals such as g.app, g.app.gui, etc. <em>Host programs should not import leoGlobals directly</em>, because doing so would not init the g.app object properly.</p>
<p>The statement:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">c</span> <span class="o">=</span> <span class="n">controller</span><span class="o">.</span><span class="n">openLeoFile</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
</pre></div>
</div>
<p>invisibly opens the .leo file given by the path argument. This call returns a completely standard Leo commander, properly inited. This is the big payoff from the leoBridge module: the host program gets instant access to c.config.getBool, etc. Do you see how sweet this is?</p>
<p>For example, the following script runs leo/test/leoBridgeTest.py outside of Leo. leoBridgeTest.py uses the leoBridge module to run all unit tests in leo/test/unitTest.leo:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span><span class="o">,</span><span class="nn">sys</span>

<span class="n">path</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">os_path_abspath</span><span class="p">(</span>
    <span class="n">g</span><span class="o">.</span><span class="n">os_path_join</span><span class="p">(</span>
        <span class="n">g</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">loadDir</span><span class="p">,</span><span class="s1">&#39;..&#39;</span><span class="p">,</span><span class="s1">&#39;test&#39;</span><span class="p">,</span><span class="s1">&#39;leoBridgeTest.py&#39;</span><span class="p">))</span>

<span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%s</span><span class="s1"> </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">executable</span><span class="p">,</span><span class="n">path</span><span class="p">))</span>
</pre></div>
</div>
<p>The file leo/test/test.leo contains the source code for leoBridgeTest.py. Here it is, stripped of its sentinel lines:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="sd">&#39;&#39;&#39;A program to run unit tests with the leoBridge module.&#39;&#39;&#39;</span>

<span class="kn">import</span> <span class="nn">leo.core.leoBridge</span> <span class="k">as</span> <span class="nn">leoBridge</span>
<span class="kn">import</span> <span class="nn">leo.core.leoTest</span> <span class="k">as</span> <span class="nn">leoTest</span>

<span class="k">def</span> <span class="nf">main</span> <span class="p">():</span>
    <span class="n">tag</span> <span class="o">=</span> <span class="s1">&#39;leoTestBridge&#39;</span>

    <span class="c1"># Setting verbose=True prints messages that would be sent to the log pane.</span>
    <span class="n">bridge</span> <span class="o">=</span> <span class="n">leoBridge</span><span class="o">.</span><span class="n">controller</span><span class="p">(</span><span class="n">gui</span><span class="o">=</span><span class="s1">&#39;nullGui&#39;</span><span class="p">,</span><span class="n">verbose</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">bridge</span><span class="o">.</span><span class="n">isOpen</span><span class="p">():</span>
        <span class="n">g</span> <span class="o">=</span> <span class="n">bridge</span><span class="o">.</span><span class="n">globals</span><span class="p">()</span>
        <span class="n">path</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">os_path_abspath</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">os_path_join</span><span class="p">(</span>
            <span class="n">g</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">loadDir</span><span class="p">,</span><span class="s1">&#39;..&#39;</span><span class="p">,</span><span class="s1">&#39;test&#39;</span><span class="p">,</span><span class="s1">&#39;unitTest.leo&#39;</span><span class="p">))</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">bridge</span><span class="o">.</span><span class="n">openLeoFile</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
        <span class="n">g</span><span class="o">.</span><span class="n">es</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%s</span><span class="s1"> </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">tag</span><span class="p">,</span><span class="n">c</span><span class="o">.</span><span class="n">shortFileName</span><span class="p">()))</span>
        <span class="n">runUnitTests</span><span class="p">(</span><span class="n">c</span><span class="p">,</span><span class="n">g</span><span class="p">)</span>

    <span class="nb">print</span> <span class="n">tag</span><span class="p">,</span><span class="s1">&#39;done&#39;</span>

<span class="k">def</span> <span class="nf">runUnitTests</span> <span class="p">(</span><span class="n">c</span><span class="p">,</span><span class="n">g</span><span class="p">):</span>
    <span class="n">nodeName</span> <span class="o">=</span> <span class="s1">&#39;All unit tests&#39;</span> <span class="c1"># The tests to run.</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">u</span> <span class="o">=</span> <span class="n">leoTest</span><span class="o">.</span><span class="n">testUtils</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
        <span class="n">p</span> <span class="o">=</span> <span class="n">u</span><span class="o">.</span><span class="n">findNodeAnywhere</span><span class="p">(</span><span class="n">nodeName</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">p</span><span class="p">:</span>
            <span class="n">g</span><span class="o">.</span><span class="n">es</span><span class="p">(</span><span class="s1">&#39;running unit tests in </span><span class="si">%s</span><span class="s1">...&#39;</span> <span class="o">%</span> <span class="n">nodeName</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">selectPosition</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">debugCommands</span><span class="o">.</span><span class="n">runUnitTests</span><span class="p">()</span>
            <span class="n">g</span><span class="o">.</span><span class="n">es</span><span class="p">(</span><span class="s1">&#39;unit tests complete&#39;</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">g</span><span class="o">.</span><span class="n">es</span><span class="p">(</span><span class="s1">&#39;node not found:&#39;</span> <span class="o">%</span> <span class="n">nodeName</span><span class="p">)</span>
    <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
        <span class="n">g</span><span class="o">.</span><span class="n">es</span><span class="p">(</span><span class="s1">&#39;unexpected exception&#39;</span><span class="p">)</span>
        <span class="n">g</span><span class="o">.</span><span class="n">es_exception</span><span class="p">()</span>
        <span class="k">raise</span>

<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
    <span class="n">main</span><span class="p">()</span>
</pre></div>
</div>
</section>
<section id="running-leobridge-from-within-leo">
<h2><a class="toc-backref" href="#id2">Running leoBridge from within Leo</a><a class="headerlink" href="#running-leobridge-from-within-leo" title="Permalink to this heading">¶</a></h2>
<p>This following is adapted from Terry Brown’s entry in Leo’s wiki.</p>
<p>You can not just run leoBridge from Leo, because the leoBridge module is designed to run a separate copy of Leo. However, it is possible to run leoBridge from a separate process. That turned out to be more, um, interesting than anticipated, so I’m recording the results here.</p>
<p>The idea is that script A running in Leo (i.e. in a regular GUI Leo session) calls script B through subprocess.Popen(), script B uses LeoBridge to do something (parse unloaded Leo files), and returns the result to script A. Passing the result back via the clipboard seemed like a possibility, but XWindows clipboard madness being what it is, that didn’t seem to work.</p>
<p>First trick, calling script B from script A:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">subprocess</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">Popen</span><span class="p">((</span><span class="s1">&#39;python&#39;</span><span class="p">,</span>
    <span class="n">path_to_script_B</span><span class="p">,</span>
    <span class="n">parameter_for_script_B</span><span class="p">,),</span>
    <span class="n">stdout</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">PIPE</span><span class="p">,</span>
    <span class="n">env</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;PYTHONPATH&#39;</span><span class="p">:</span> <span class="n">g</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">loadDir</span><span class="p">,</span><span class="s1">&#39;USER&#39;</span><span class="p">:</span> <span class="n">g</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">leoID</span><span class="p">},</span>
<span class="p">)</span>
<span class="n">p</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
</pre></div>
</div>
<p>Setting PYTHONPATH in the environment seemed like the easiest way to let script B find leoBridge.py (which it needs to import).  But by setting the env parameter you limit script B’s environment to be <strong>only</strong> PYTHONPATH, which causes leoBridge to fail because, in unix at least, it depends on USER in the environment.  So you need to pass that through, too.</p>
<p>Now, because passing stuff back on the clipboard seems unreliable, at least in XWindows, script B passes results back to script A via stdout (print), but there’s some Leo initialization chatter you want to avoid.  So put a sentinel, ‘START_CLIPBOARD’, in the output, and collect it like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">response</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="k">while</span> <span class="n">response</span> <span class="ow">and</span> <span class="s1">&#39;START_CLIPBOARD&#39;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">response</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
    <span class="k">del</span> <span class="n">response</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">del</span> <span class="n">response</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>  <span class="c1"># delete the sentinel as well</span>
<span class="n">response</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">response</span><span class="p">)</span>
</pre></div>
</div>
<p>This is the basic mechanism.  What I <em>actually</em> wanted to do was have script B generate a branch of nodes and pass that back to script A for insertion in the tree script A is running in.  That’s relatively easy if you use:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">c</span><span class="o">.</span><span class="n">setCurrentPosition</span><span class="p">(</span><span class="n">pos_of_branch_to_return</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">copyOutline</span><span class="p">()</span>
<span class="nb">print</span> <span class="s1">&#39;&lt;!-- START_CLIPBOARD --&gt;&#39;</span>
<span class="nb">print</span> <span class="n">g</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">gui</span><span class="o">.</span><span class="n">getTextFromClipboard</span><span class="p">()</span>
<span class="nb">print</span> <span class="s1">&#39;&lt;!-- END_CLIPBOARD --&gt;&#39;</span>
</pre></div>
</div>
<p>at the end of script B. Back in script A, after you’ve rebuilt
<cite>response</cite> as shown above, do:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">g</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">gui</span><span class="o">.</span><span class="n">replaceClipboardWith</span><span class="p">(</span><span class="n">response</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">pasteOutline</span><span class="p">()</span>
</pre></div>
</div>
</section>
</section>


            <div class="clearer"></div>
          </div>
        </div>
      </div>
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
            <p class="logo"><a href="leo_toc.html">
              <img class="logo" src="_static/LeoLogo.svg" alt="Logo"/>
            </a></p>
  <div>
    <h4>Previous topic</h4>
    <p class="topless"><a href="vimBindings.html"
                          title="previous chapter">Using Vim with Leo</a></p>
  </div>
  <div>
    <h4>Next topic</h4>
    <p class="topless"><a href="IPythonBridge.html"
                          title="next chapter">ILeo: Leo’s IPython Bridge</a></p>
  </div>
<div id="searchbox" style="display: none" role="search">
  <h3 id="searchlabel">Quick search</h3>
    <div class="searchformwrapper">
    <form class="search" action="search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>
    </div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
        </div>
<div id="sidebarbutton" title="Collapse sidebar">
<span>«</span>
</div>

      </div>
      <div class="clearer"></div>
    </div>
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="genindex.html" title="General Index"
             >index</a></li>
        <li class="right" >
          <a href="IPythonBridge.html" title="ILeo: Leo’s IPython Bridge"
             >next</a> |</li>
        <li class="right" >
          <a href="vimBindings.html" title="Using Vim with Leo"
             >previous</a> |</li>
        <li class="nav-item nav-item-0"><a href="leo_toc.html">Leo 6.7.2 documentation</a> &#187;</li>
          <li class="nav-item nav-item-1"><a href="leoandotherprograms.html" >Leo and Other Programs</a> &#187;</li>
        <li class="nav-item nav-item-this"><a href="">Embedding Leo with the leoBridge module</a></li> 
      </ul>
    </div>
    <div class="footer" role="contentinfo">
        &#169; Copyright 1997-2023, Edward K. Ream.
      Last updated on February 28, 2023.
      Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 5.3.0.
    </div>
  </body>
</html>